﻿using GKS.Math.LinearAlgebra;
using System;


namespace TestConsoleApp.Math.LinearAlgebra {
    public static class MatrixTests {
        #region variables

        #endregion

        #region properties

        #endregion

        #region enums

        #endregion

        #region constructors

        #endregion

        #region methods
        public static Matrix<int> CreateRandomMatrix(int dimension = 2) {
            return CreateRandomMatrix(dimension, dimension);
        }

        public static Matrix<int> CreateRandomMatrix(int rows, int columns) {
            Matrix<int> result = new Matrix<int>(rows, columns);
            Random randomIntGenerator = new Random();

            for (int i = 0; i < rows; i++) {
                for (int j = 0; j < columns; j++) {
                    result[i, j] = randomIntGenerator.Next(10);
                }
            }

            return result;
        }

        #region sync methods tests
        public static void ToStringTest() {
            Matrix<int> m1 = CreateRandomMatrix(3),
                        m2 = CreateRandomMatrix(3, 5),
                        m3,
                        m4;

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("m2:\n{0}", m2);

            try {
                m3 = CreateRandomMatrix(0);
                Console.WriteLine("The creation of the Matrix with dimension 0 shouldn't have happened.");
            } catch (Exception e) {
                Console.WriteLine("As expected, the creation of a Matrix with dimension 0 threw an Exception.");
            }

            try {
                m4 = CreateRandomMatrix(-1, -2);
                Console.WriteLine("The creation of the Matrix with negative row and column sizes shouldn't have happened.");
            } catch (Exception e) {
                Console.WriteLine("As expected, the creation of a Matrix with negative row and column sizes threw an Exception.");
            }
        }

        public static void AddTest() {
            Matrix<int> m1 = CreateRandomMatrix(3),
                        m2 = CreateRandomMatrix(3),
                        m3 = CreateRandomMatrix(4),
                        m4;

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("m2:\n{0}", m2);
            Console.WriteLine("m3:\n{0}", m3);
            Console.WriteLine("m1 + m2:\n{0}", m1 + m2);

            try {
                m4 = m2 + m3;
                Console.WriteLine("The sum between a 3x3 and a 4x4 matrix happened, and it shouldn't have.");
            } catch (Exception e) {
                Console.WriteLine("As expected, the sum between matrices with different sizes threw an exception.");
            }
        }

        public static void MultiplicationTest() {
            Matrix<int> m1 = CreateRandomMatrix(3);
            Matrix<int> m2 = CreateRandomMatrix(3, 4);
            Matrix<int> m3 = CreateRandomMatrix(4);
            Matrix<int> m4 = CreateRandomMatrix();

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("m2:\n{0}", m2);
            Console.WriteLine("m3:\n{0}", m3);
            Console.WriteLine("m4:\n{0}", m4);

            Console.WriteLine("m1 x m2:\n{0}", m1 * m2);
            Console.WriteLine("m2 x m3:\n{0}", m2 * m3);

            try { Console.WriteLine("m3 x m4:\n{0}", m3 * m4); } 
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        public static void ScalarMultiplicationTest() {
            Matrix<int> m1 = CreateRandomMatrix(3);
            Matrix<int> m2 = CreateRandomMatrix(3, 4);
            int multiplicator = 3;

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("m2:\n{0}", m2);
            Console.WriteLine("multiplicator = {0}", multiplicator);
            Console.WriteLine("m1 * multiplicator:\n{0}", m1 * multiplicator);
            Console.WriteLine("m2 * multiplicator:\n{0}", m2 * multiplicator);
        }

        public static void TransposeTest() {
            Matrix<int> m1 = CreateRandomMatrix(4);
            Matrix<int> m2 = CreateRandomMatrix(3, 5);

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("T(m1):\n{0}", m1.Transpose());
            Console.WriteLine("m2:\n{0}", m2);
            Console.WriteLine("T(m2):\n{0}", m2.Transpose());
        }

        public static void GetTraceTest() {
            Matrix<int> m1 = CreateRandomMatrix();
            Matrix<int> m2 = CreateRandomMatrix(3);
            Matrix<int> m3 = CreateRandomMatrix(4);
            Matrix<int> m4 = CreateRandomMatrix(2, 4);

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("Trace(m1): {0}\n", m1.GetTrace());
            Console.WriteLine("m2:\n{0}", m2);
            Console.WriteLine("Trace(m2): {0}\n", m2.GetTrace());
            Console.WriteLine("m3:\n{0}", m3);
            Console.WriteLine("Trace(m3): {0}\n", m3.GetTrace());
            Console.WriteLine("m4:\n{0}", m4);
            try { Console.WriteLine("Trace(m4):\n{0}", m4.GetTrace()); } 
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        public static void GetDeterminantTest() {
            Matrix<int> m1 = CreateRandomMatrix();
            Matrix<int> m2 = CreateRandomMatrix(3);
            Matrix<int> m3 = CreateRandomMatrix(4);
            Matrix<int> m4 = CreateRandomMatrix(2, 4);

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("Determinant(m1): {0}\n", m1.GetDeterminant());
            Console.WriteLine("m2:\n{0}", m2);
            Console.WriteLine("Determinant(m2): {0}\n", m2.GetDeterminant());
            Console.WriteLine("m3:\n{0}", m3);
            Console.WriteLine("Determinant(m3): {0}\n", m3.GetDeterminant());
            Console.WriteLine("m4:\n{0}", m4);
            try { Console.WriteLine("Determinant(m4):\n{0}", m4.GetDeterminant()); } 
            catch (Exception e) { Console.WriteLine(e.Message); }
        }

        public static void EqualityTest() {
            Matrix<int> m1 = CreateRandomMatrix();
            Matrix<int> m2 = CreateRandomMatrix(3);
            Matrix<int> m3 = CreateRandomMatrix(4);
            Matrix<int> m4 = CreateRandomMatrix(2, 4);
            Matrix<int> m5 = m1;

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("m2:\n{0}", m2);
            Console.WriteLine("m3:\n{0}", m3);
            Console.WriteLine("m4:\n{0}", m4);
            Console.WriteLine("m5:\n{0}", m5);

            Console.WriteLine("m1 == m2: {0}", m1 == m2);
            Console.WriteLine("m1 != m2: {0}", m1 != m2);
            Console.WriteLine("m2 == m3: {0}", m2 == m3);
            Console.WriteLine("m2 != m3: {0}", m2 != m3);
            Console.WriteLine("m3 == m4: {0}", m3 == m4);
            Console.WriteLine("m3 != m4: {0}", m3 != m4);
            Console.WriteLine("m1 == m5: {0}", m1 == m5);
            Console.WriteLine("m1 != m5: {0}", m1 != m5);
        }

        public static void IsSquareTest() {
            Matrix<int> m1 = CreateRandomMatrix();
            Matrix<int> m2 = CreateRandomMatrix(4);
            Matrix<int> m3 = CreateRandomMatrix(2, 4);

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("IsSquare(m1): {0}\n", m1.IsSquare);
            Console.WriteLine("m2:\n{0}", m2);
            Console.WriteLine("IsSquare(m2): {0}\n", m2.IsSquare);
            Console.WriteLine("m3:\n{0}", m3);
            Console.WriteLine("IsSquare(m3): {0}\n", m3.IsSquare);
        }

        public static void IsSymmetricTest() {
            Matrix<int> m1 = CreateRandomMatrix();
            Matrix<int> m2 = CreateRandomMatrix(4);
            Matrix<int> m3 = CreateRandomMatrix(2, 4);
            Matrix<int> m4 = CreateRandomMatrix(5);

            for (int i = 0; i < m4.Rows; i++) {
                for (int j = i; j < m4.Columns; j++) {
                    m4[i, j] = m4[j, i];
                }
            }

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("IsSymmetric(m1): {0}\n", m1.IsSymmetric);
            Console.WriteLine("m2:\n{0}", m2);
            Console.WriteLine("IsSymmetric(m2): {0}\n", m2.IsSymmetric);
            Console.WriteLine("m3:\n{0}", m3);
            Console.WriteLine("IsSymmetric(m3): {0}\n", m3.IsSymmetric);
            Console.WriteLine("m4:\n{0}", m4);
            Console.WriteLine("IsSymmetric(m4): {0}\n", m4.IsSymmetric);
        }

        public static void GetHashCodeTest() {
            Matrix<int> m1 = CreateRandomMatrix();
            Matrix<int> m2 = CreateRandomMatrix(4);
            Matrix<int> m3 = CreateRandomMatrix(2, 4);
            Matrix<int> m4 = CreateRandomMatrix(5);

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("hash(m1): {0}\n", m1.GetHashCode());
            Console.WriteLine("m2:\n{0}", m2);
            Console.WriteLine("hash(m2): {0}\n", m2.GetHashCode());
            Console.WriteLine("m3:\n{0}", m3);
            Console.WriteLine("hash(m3): {0}\n", m3.GetHashCode());
            Console.WriteLine("m3:\n{0}", m4);
            Console.WriteLine("hash(m4): {0}\n", m4.GetHashCode());
        }

        public static void GetMultiplicationIdentityTest() {
            Matrix<int> m1 = Matrix<int>.GetMultiplicationIdentity();
            Matrix<int> m2 = Matrix<int>.GetMultiplicationIdentity(4);

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("m2:\n{0}", m2);
        }

        public static void GetSumIdentityTest() {
            Matrix<int> m1 = Matrix<int>.GetSumIdentity(2, 2);
            Matrix<int> m2 = Matrix<int>.GetSumIdentity(4, 4);

            Console.WriteLine("m1:\n{0}", m1);
            Console.WriteLine("m2:\n{0}", m2);
        }
        #endregion

        #region async methods tests

        #endregion
        #endregion
    }
}
